﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Diagnostics;

namespace AndersLiu.PE
{
    public class CliHeader : ImageData
    {
        public U4Field Cb { get; private set; }
        public U2Field MajorRuntimeVersion { get; private set; }
        public U2Field MinorRuntimeVersion { get; private set; }
        public ImageDataDirectory MetaData { get; private set; }
        public ComImageFlagsField Flags { get; private set; }
        public U4Field EntryPointToken { get; private set; }
        public ImageDataDirectory Resources { get; private set; }
        public ImageDataDirectory StrongNameSignature { get; private set; }
        public ImageDataDirectory CodeManagerTable { get; private set; }
        public ImageDataDirectory VTableFixups { get; private set; }
        public ImageDataDirectory ExportAddressTableJumps { get; private set; }
        public ImageDataDirectory ManagedNativeHeader { get; private set; }

        internal CliHeader(PEFile image, uint offset)
            : base(image, offset)
        {
            var pos = offset;

            this.Cb = new U4Field(image, pos);
            pos += this.Cb.RawDataSize;

            this.MajorRuntimeVersion = new U2Field(image, pos);
            pos += this.MajorRuntimeVersion.RawDataSize;

            this.MinorRuntimeVersion = new U2Field(image, pos);
            pos += this.MinorRuntimeVersion.RawDataSize;

            this.MetaData = new ImageDataDirectory(image, pos);
            pos += this.MetaData.RawDataSize;

            this.Flags = new ComImageFlagsField(image, pos);
            pos += this.Flags.RawDataSize;

            this.EntryPointToken = new U4Field(image, pos);
            pos += this.EntryPointToken.RawDataSize;

            this.Resources = new ImageDataDirectory(image, pos);
            pos += this.Resources.RawDataSize;

            this.StrongNameSignature = new ImageDataDirectory(image, pos);
            pos += this.StrongNameSignature.RawDataSize;

            this.CodeManagerTable = new ImageDataDirectory(image, pos);
            pos += this.CodeManagerTable.RawDataSize;

            this.VTableFixups = new ImageDataDirectory(image, pos);
            pos += this.VTableFixups.RawDataSize;

            this.ExportAddressTableJumps = new ImageDataDirectory(image, pos);
            pos += this.ExportAddressTableJumps.RawDataSize;

            this.ManagedNativeHeader = new ImageDataDirectory(image, pos);
            pos += this.ManagedNativeHeader.RawDataSize;

            SetSize(pos - offset);
        }
    }

    public class ComImageFlagsField : Field<ComImageFlags>
    {
        internal ComImageFlagsField(PEFile image, uint offset)
            : base(image, offset, 4)
        {
        }

        protected override ComImageFlags ParseValue(byte[] rawData)
        {
            return (ComImageFlags)BitConverter.ToUInt32(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    public class MetadataRoot : ImageData
    {
        public const uint MetadataSignature = 0x424A5342;

        public MetadataSignatureField Signature { get; private set; }
        public U2Field MajorVersion { get; private set; }
        public U2Field MinorVersion { get; private set; }
        public U4Field Reserved { get; private set; }
        public U4Field VersionStringLength { get; private set; }
        public FixedSizeUtf8StringField Version { get; private set; }
        public FixedSizeByteArrayField Padding { get; private set; }
        public U2Field Flags { get; private set; }
        public U2Field NumberOfStreams { get; private set; }
        public StreamHeaders StreamHeaders { get; private set; }

        internal MetadataRoot(PEFile image, uint offset)
            : base(image, offset)
        {
            var pos = offset;

            this.Signature = new MetadataSignatureField(image, pos);
            pos += this.Signature.RawDataSize;

            this.MajorVersion = new U2Field(image, pos);
            pos += this.MajorVersion.RawDataSize;

            this.MinorVersion = new U2Field(image, pos);
            pos += this.MinorVersion.RawDataSize;

            this.Reserved = new U4Field(image, pos);
            pos += this.Reserved.RawDataSize;

            this.VersionStringLength = new U4Field(image, pos);
            pos += this.VersionStringLength.RawDataSize;

            var verLen = this.VersionStringLength.Value;
            var rem = verLen % 4;
            var padLen = rem > 0 ? 4 - rem : 0;

            this.Version = new FixedSizeUtf8StringField(image, pos, verLen);
            pos += this.Version.RawDataSize;

            this.Padding = new FixedSizeByteArrayField(image, pos, padLen);
            pos += this.Padding.RawDataSize;

            this.Flags = new U2Field(image, pos);
            pos += this.Flags.RawDataSize;

            this.NumberOfStreams = new U2Field(image, pos);
            pos += this.NumberOfStreams.RawDataSize;

            this.StreamHeaders = new StreamHeaders(image, pos, this.NumberOfStreams.Value);
            pos += this.StreamHeaders.RawDataSize;

            SetSize(pos - offset);
        }
    }

    public class MetadataSignatureField : U4Field
    {
        internal MetadataSignatureField(PEFile image, uint offset)
            : base(image, offset)
        {
        }

        protected override string GetValueString()
        {
            var rawData = GetRawData();
            var str = Encoding.ASCII.GetString(rawData);

            return string.Format("{0:X8}h ('{1}')", this.Value, str);
        }
    }

    public class StreamHeader : ImageData
    {
        public U4Field Offset { get; private set; }
        public U4Field Size { get; private set; }
        public NullTerminatedUtf8StringField Name { get; private set; }
        public FixedSizeByteArrayField Padding { get; private set; }

        internal StreamHeader(PEFile image, uint offset)
            : base(image, offset)
        {
            var pos = offset;

            this.Offset = new U4Field(image, pos);
            pos += this.Offset.RawDataSize;

            this.Size = new U4Field(image, pos);
            pos += this.Size.RawDataSize;

            this.Name = new NullTerminatedUtf8StringField(image, pos);
            pos += this.Name.RawDataSize;

            var rem = this.Name.RawDataSize % 4;
            var padLen = rem > 0 ? 4 - rem : 0;

            this.Padding = new FixedSizeByteArrayField(image, pos, padLen);
            pos += this.Padding.RawDataSize;

            SetSize(pos - offset);
        }
    }

    public class StreamHeaders : ImageData, IEnumerable<StreamHeader>
    {
        public StreamHeader this[int index]
        {
            get
            {
                if (index < 0 || index >= this._streams.Length)
                    throw new StreamNotFoundException();

                return this._streams[index];
            }
        }

        public int Count
        {
            get
            {
                return this._streams.Length;
            }
        }

        public StreamHeader this[string name]
        {
            get
            {
                for (var i = 0; i < this._streams.Length; i++)
                {
                    if (this[i].Name.Value.Equals(name))
                        return this[i];
                }

                return null;
            }
        }

        public IEnumerator<StreamHeader> GetEnumerator()
        {
            for (var i = 0; i < _streams.Length; i++)
                yield return _streams[i];
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal StreamHeaders(PEFile image, uint offset, int numStreams)
            : base(image, offset)
        {
            var pos = offset;
            //var numStreams = image.MetadataRoot.NumberOfStreams.Value;

            _streams = new StreamHeader[numStreams];

            for (var i = 0; i < numStreams; i++)
            {
                _streams[i] = new StreamHeader(image, pos);
                pos += _streams[i].RawDataSize;
            }

            SetSize(pos - offset);
        }

        private StreamHeader[] _streams;
    }

    public static class MetadataStreamNames
    {
        public const string Table = "#~";
        public const string Strings = "#Strings";
        public const string UserStrings = "#US";
        public const string Guid = "#GUID";
        public const string Blob = "#Blob";
    }

    public class StringsStream : ImageData, IEnumerable<StringsStreamItem>
    {
        public StringsStreamItem GetItem(uint offset)
        {
            return new StringsStreamItem(this.PEFile, this.FileOffset + offset);
        }

        public IEnumerator<StringsStreamItem> GetEnumerator()
        {
            var offset = (uint)0;
            while (offset < this.RawDataSize)
            {
                var item = GetItem(offset);
                offset += item.RawDataSize;

                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal StringsStream(PEFile image, uint offset, uint size)
            : base(image, offset, size)
        {
        }
    }

    public class StringsStreamItem : NullTerminatedUtf8StringField
    {
        public uint StreamOffset
        {
            get { return this.FileOffset - this.PEFile.StringsStream.FileOffset; }
        }

        internal StringsStreamItem(PEFile image, uint offset)
            : base(image, offset)
        {
        }
    }

    public class UserStringsStream : ImageData, IEnumerable<UserStringsStreamItem>
    {
        public UserStringsStreamItem GetItem(uint offset)
        {
            return new UserStringsStreamItem(this.PEFile, this.FileOffset + offset);
        }

        public IEnumerator<UserStringsStreamItem> GetEnumerator()
        {
            var offset = (uint)0;
            while (offset < this.RawDataSize)
            {
                var item = GetItem(offset);
                offset += item.RawDataSize;

                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal UserStringsStream(PEFile image, uint offset, uint size)
            : base(image, offset, size)
        {
        }
    }

    public class UserStringsStreamItem : ImageData
    {
        public CompressedUIntField Size { get; private set; }
        public FixedSizeUnicodeStringField UserString { get; private set; }
        public FixedSizeByteArrayField Suffix { get; private set; }

        public uint StreamOffset
        {
            get { return this.FileOffset - this.PEFile.UserStringsStream.FileOffset; }
        }

        internal UserStringsStreamItem(PEFile image, uint offset)
            : base(image, offset)
        {
            var pos = offset;

            this.Size = new CompressedUIntField(image, pos);
            pos += this.Size.RawDataSize;

            var strLen = this.Size.Value > 0 ? this.Size.Value - 1 : 0;
            var sufLen = strLen > 0 ? (uint)1 : 0;

            this.UserString = new FixedSizeUnicodeStringField(image, pos, strLen);
            pos += this.UserString.RawDataSize;

            this.Suffix = new FixedSizeByteArrayField(image, pos, sufLen);
            pos += this.Suffix.RawDataSize;

            SetSize(pos - offset);
        }
    }

    public class GuidStream : ImageData, IEnumerable<GuidStreamItem>
    {
        public GuidStreamItem GetItem(uint index)
        {
            return new GuidStreamItem(this.PEFile, this.FileOffset + index * GuidStreamItem.ItemSize);
        }

        public IEnumerator<GuidStreamItem> GetEnumerator()
        {
            var offset = (uint)0;
            var index = (uint)0;

            while (offset < this.RawDataSize)
            {
                var item = GetItem(index);
                offset += GuidStreamItem.ItemSize;
                index++;

                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal GuidStream(PEFile image, uint offset, uint size)
            : base(image, offset, size)
        {
        }
    }

    public class GuidStreamItem : GuidField
    {
        public const int ItemSize = 16;

        public uint Index
        {
            get { return (this.FileOffset - this.PEFile.GuidStream.FileOffset) / ItemSize + 1; }
        }

        internal GuidStreamItem(PEFile image, uint offset)
            : base(image, offset)
        {
        }
    }

    public class BlobStream : ImageData, IEnumerable<BlobStreamItem>
    {
        public BlobStreamItem GetItem(uint offset)
        {
            return new BlobStreamItem(this.PEFile, this.FileOffset + offset);
        }

        public IEnumerator<BlobStreamItem> GetEnumerator()
        {
            var offset = (uint)0;
            while (offset < this.RawDataSize)
            {
                var item = GetItem(offset);
                offset += item.RawDataSize;

                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal BlobStream(PEFile image, uint offset, uint size)
            : base(image, offset, size)
        {
        }
    }

    public class BlobStreamItem : ImageData
    {
        public CompressedUIntField Size { get; private set; }
        public FixedSizeByteArrayField Blob { get; private set; }

        public uint StreamOffset
        {
            get { return this.FileOffset - this.PEFile.BlobStream.FileOffset; }
        }

        internal BlobStreamItem(PEFile image, uint offset)
            : base(image, offset)
        {
            var pos = offset;

            this.Size = new CompressedUIntField(image, pos);
            pos += this.Size.RawDataSize;

            this.Blob = new FixedSizeByteArrayField(image, pos, this.Size.Value);
            pos += this.Blob.RawDataSize;

            SetSize(pos - offset);
        }
    }

    public class TableStream : ImageData
    {
        public static readonly uint NumberOfTables = (uint)TableIndex.MaxTables;

        public TableHeader TableHeader { get; private set; }

        public ModuleTable ModuleTable { get; private set; }
        public TypeRefTable TypeRefTable { get; private set; }
        public TypeDefTable TypeDefTable { get; private set; }
        public FieldPtrTable FieldPtrTable { get; private set; }
        public FieldTable FieldTable { get; private set; }
        public MethodPtrTable MethodPtrTable { get; private set; }
        public MethodDefTable MethodDefTable { get; private set; }
        public ParamPtrTable ParamPtrTable { get; private set; }
        public ParamTable ParamTable { get; private set; }
        public InterfaceImplTable InterfaceImplTable { get; private set; }
        public MemberRefTable MemberRefTable { get; private set; }
        public ConstantTable ConstantTable { get; private set; }
        public CustomAttributeTable CustomAttributeTable { get; private set; }
        public FieldMarshalTable FieldMarshalTable { get; private set; }
        public DeclSecurityTable DeclSecurityTable { get; private set; }
        public ClassLayoutTable ClassLayoutTable { get; private set; }
        public FieldLayoutTable FieldLayoutTable { get; private set; }
        public StandAloneSigTable StandAloneSigTable { get; private set; }
        public EventMapTable EventMapTable { get; private set; }
        public EventPtrTable EventPtrTable { get; private set; }
        public EventTable EventTable { get; private set; }
        public PropertyMapTable PropertyMapTable { get; private set; }
        public PropertyPtrTable PropertyPtrTable { get; private set; }
        public PropertyTable PropertyTable { get; private set; }
        public MethodSemanticsTable MethodSemanticsTable { get; private set; }
        public MethodImplTable MethodImplTable { get; private set; }
        public ModuleRefTable ModuleRefTable { get; private set; }
        public TypeSpecTable TypeSpecTable { get; private set; }
        public ImplMapTable ImplMapTable { get; private set; }
        public FieldRvaTable FieldRvaTable { get; private set; }
        public EncLogTable EncLogTable { get; private set; }
        public EncMapTable EncMapTable { get; private set; }
        public AssemblyTable AssemblyTable { get; private set; }
        public AssemblyProcessorTable AssemblyProcessorTable { get; private set; }
        public AssemblyOSTable AssemblyOSTable { get; private set; }
        public AssemblyRefTable AssemblyRefTable { get; private set; }
        public AssemblyRefProcessorTable AssemblyRefProcessorTable { get; private set; }
        public AssemblyRefOSTable AssemblyRefOSTable { get; private set; }
        public FileTable FileTable { get; private set; }
        public ExportedTypeTable ExportedTypeTable { get; private set; }
        public ManifestResourceTable ManifestResourceTable { get; private set; }
        public NestedClassTable NestedClassTable { get; private set; }
        public GenericParamTable GenericParamTable { get; private set; }
        public MethodSpecTable MethodSpecTable { get; private set; }
        public GenericParamConstraintTable GenericParamConstraintTable { get; private set; }

        internal TableStream(PEFile image, uint offset, uint size)
            : base(image, offset, size)
        {
            var pos = offset;

            this.TableHeader = new TableHeader(image, pos);
            pos += this.TableHeader.RawDataSize;

            if (this.TableHeader.IsTableValid(TableIndex.Module))
            {
                this.ModuleTable = new ModuleTable(this.TableHeader, pos);
                pos += this.ModuleTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.TypeRef))
            {
                this.TypeRefTable = new TypeRefTable(this.TableHeader, pos);
                pos += this.TypeRefTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.TypeDef))
            {
                this.TypeDefTable = new TypeDefTable(this.TableHeader, pos);
                pos += this.TypeDefTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.FieldPtr))
            {
                this.FieldPtrTable = new FieldPtrTable(this.TableHeader, pos);
                pos += this.FieldPtrTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.Field))
            {
                this.FieldTable = new FieldTable(this.TableHeader, pos);
                pos += this.FieldTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.MethodPtr))
            {
                this.MethodPtrTable = new MethodPtrTable(this.TableHeader, pos);
                pos += this.MethodPtrTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.MethodDef))
            {
                this.MethodDefTable = new MethodDefTable(this.TableHeader, pos);
                pos += this.MethodDefTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.ParamPtr))
            {
                this.ParamPtrTable = new ParamPtrTable(this.TableHeader, pos);
                pos += this.ParamPtrTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.Param))
            {
                this.ParamTable = new ParamTable(this.TableHeader, pos);
                pos += this.ParamTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.InterfaceImpl))
            {
                this.InterfaceImplTable = new InterfaceImplTable(this.TableHeader, pos);
                pos += this.InterfaceImplTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.MemberRef))
            {
                this.MemberRefTable = new MemberRefTable(this.TableHeader, pos);
                pos += this.MemberRefTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.Constant))
            {
                this.ConstantTable = new ConstantTable(this.TableHeader, pos);
                pos += this.ConstantTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.CustomAttribute))
            {
                this.CustomAttributeTable = new CustomAttributeTable(this.TableHeader, pos);
                pos += this.CustomAttributeTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.FieldMarshal))
            {
                this.FieldMarshalTable = new FieldMarshalTable(this.TableHeader, pos);
                pos += this.FieldMarshalTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.DeclSecurity))
            {
                this.DeclSecurityTable = new DeclSecurityTable(this.TableHeader, pos);
                pos += this.DeclSecurityTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.ClassLayout))
            {
                this.ClassLayoutTable = new ClassLayoutTable(this.TableHeader, pos);
                pos += this.ClassLayoutTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.FieldLayout))
            {
                this.FieldLayoutTable = new FieldLayoutTable(this.TableHeader, pos);
                pos += this.FieldLayoutTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.StandAloneSig))
            {
                this.StandAloneSigTable = new StandAloneSigTable(this.TableHeader, pos);
                pos += this.StandAloneSigTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.EventMap))
            {
                this.EventMapTable = new EventMapTable(this.TableHeader, pos);
                pos += this.EventMapTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.EventPtr))
            {
                this.EventPtrTable = new EventPtrTable(this.TableHeader, pos);
                pos += this.EventPtrTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.Event))
            {
                this.EventTable = new EventTable(this.TableHeader, pos);
                pos += this.EventTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.PropertyMap))
            {
                this.PropertyMapTable = new PropertyMapTable(this.TableHeader, pos);
                pos += this.PropertyMapTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.PropertyPtr))
            {
                this.PropertyPtrTable = new PropertyPtrTable(this.TableHeader, pos);
                pos += this.PropertyPtrTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.Property))
            {
                this.PropertyTable = new PropertyTable(this.TableHeader, pos);
                pos += this.PropertyTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.MethodSemantics))
            {
                this.MethodSemanticsTable = new MethodSemanticsTable(this.TableHeader, pos);
                pos += this.MethodSemanticsTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.MethodImpl))
            {
                this.MethodImplTable = new MethodImplTable(this.TableHeader, pos);
                pos += this.MethodImplTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.ModuleRef))
            {
                this.ModuleRefTable = new ModuleRefTable(this.TableHeader, pos);
                pos += this.ModuleRefTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.TypeSpec))
            {
                this.TypeSpecTable = new TypeSpecTable(this.TableHeader, pos);
                pos += this.TypeSpecTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.ImplMap))
            {
                this.ImplMapTable = new ImplMapTable(this.TableHeader, pos);
                pos += this.ImplMapTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.FieldRva))
            {
                this.FieldRvaTable = new FieldRvaTable(this.TableHeader, pos);
                pos += this.FieldRvaTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.EncLog))
            {
                this.EncLogTable = new EncLogTable(this.TableHeader, pos);
                pos += this.EncLogTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.EncMap))
            {
                this.EncMapTable = new EncMapTable(this.TableHeader, pos);
                pos += this.EncMapTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.Assembly))
            {
                this.AssemblyTable = new AssemblyTable(this.TableHeader, pos);
                pos += this.AssemblyTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.AssemblyProcessor))
            {
                this.AssemblyProcessorTable = new AssemblyProcessorTable(this.TableHeader, pos);
                pos += this.AssemblyProcessorTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.AssemblyOS))
            {
                this.AssemblyOSTable = new AssemblyOSTable(this.TableHeader, pos);
                pos += this.AssemblyOSTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.AssemblyRef))
            {
                this.AssemblyRefTable = new AssemblyRefTable(this.TableHeader, pos);
                pos += this.AssemblyRefTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.AssemblyRefProcessor))
            {
                this.AssemblyRefProcessorTable = new AssemblyRefProcessorTable(this.TableHeader, pos);
                pos += this.AssemblyRefProcessorTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.AssemblyRefOS))
            {
                this.AssemblyRefOSTable = new AssemblyRefOSTable(this.TableHeader, pos);
                pos += this.AssemblyRefOSTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.File))
            {
                this.FileTable = new FileTable(this.TableHeader, pos);
                pos += this.FileTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.ExportedType))
            {
                this.ExportedTypeTable = new ExportedTypeTable(this.TableHeader, pos);
                pos += this.ExportedTypeTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.ManifestResource))
            {
                this.ManifestResourceTable = new ManifestResourceTable(this.TableHeader, pos);
                pos += this.ManifestResourceTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.NestedClass))
            {
                this.NestedClassTable = new NestedClassTable(this.TableHeader, pos);
                pos += this.NestedClassTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.GenericParam))
            {
                this.GenericParamTable = new GenericParamTable(this.TableHeader, pos);
                pos += this.GenericParamTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.MethodSpec))
            {
                this.MethodSpecTable = new MethodSpecTable(this.TableHeader, pos);
                pos += this.MethodSpecTable.RawDataSize;
            }

            if (this.TableHeader.IsTableValid(TableIndex.GenericParamConstraint))
            {
                this.GenericParamConstraintTable = new GenericParamConstraintTable(this.TableHeader, pos);
                pos += this.GenericParamConstraintTable.RawDataSize;
            }
        }
    }
}
